package it.unibo.refolding.pico.ui;

import it.unibo.refolding.common.CommonThings;
import it.unibo.refolding.common.LinearFunction;
import it.unibo.refolding.pico.ContactPointAndSlopeHelper;
import it.unibo.refolding.pico.PicoDataAnalyser.ContactPointAndSlope;
import it.unibo.refolding.pico.ZLsbDeflectionLsbPoint;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.shorts.ShortList;

import java.io.IOException;
import java.nio.file.Path;
import java.util.logging.Logger;

import org.apache.commons.lang3.builder.ReflectionToStringBuilder;

import com.google.common.base.Preconditions;

public class ContactPointAndSlopeHolder implements DataHolder {

	private static final Logger logger = Logger.getLogger(
		ContactPointAndSlopeHolder.class.getSimpleName());

	private final Path contactPointAndSlopeFile;
	private final ShortList z, def;
	private final IntList junctionPoints;
	private ZLsbDeflectionLsbPoint contactPoint;
	public double slope;

	public ContactPointAndSlopeHolder(Path contactPointAndSlopeFile,
			ShortList z, ShortList def,
			ZLsbDeflectionLsbPoint contactPoint, double slope, IntList junctionPoints) {
		Preconditions.checkArgument(Double.isNaN(slope) | contactPoint != null);
		Preconditions.checkArgument(z.size() == def.size());
		this.contactPointAndSlopeFile = contactPointAndSlopeFile;
		this.junctionPoints = junctionPoints;
		this.z = z;
		this.def = def;
		this.contactPoint = contactPoint;
		this.slope = slope;
	}

	public IntList junctionPoints() {
	  return junctionPoints;
	}
	
	public ZLsbDeflectionLsbPoint getContactPoint() {
		return contactPoint;
	}
	
	public void setContactPoint(ZLsbDeflectionLsbPoint contactPoint) {
		logger.info("The corresponding .psi file, if any, is no longer valid!");
		this.contactPoint = contactPoint;
	}
	
	@Override
	public String filename() {
		return contactPointAndSlopeFile.getFileName().toString();
	}

	@Override
	public String toString() {
		return ReflectionToStringBuilder.toString(this);
	}

	@Override
	public void save() {
		try {
			ContactPointAndSlopeHelper
					.writeToFile(contactPointAndSlope(), contactPointAndSlopeFile);
		} catch (IOException e) {
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	private ContactPointAndSlope contactPointAndSlope() {
		return new ContactPointAndSlope(contactPoint, slope);
	}

	public LinearFunction linearFunction() {
		return Double.isNaN(slope) ? null : contactPoint.linearFunctionWithSlope(slope);
	}

	@Override
	public short minZ() {
		return CommonThings.min(z);
	}

	@Override
	public short maxZ() {
		return CommonThings.max(z);
	}

	@Override
	public short minDef() {
		return CommonThings.min(def);
	}

	@Override
	public short maxDef() {
		return CommonThings.max(def);
	}

	@Override
	public ShortList sharedZ() {
		return z;
	}

	@Override
	public ShortList sharedDef() {
		return def;
	}

	@Override
	public int size() {
		return z.size();
	}

	public void setContactPointDeflectionLsb(double defLsb) {
		contactPoint = contactPoint.withDeflectionLsb(defLsb);
	}

	public double retractionContactPointZLsb() {
		return contactPoint.zLsb;
	}
}
